package org.lyfeng.spring.beans.factory.support;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.lyfeng.spring.beans.BeanFactory;
import org.lyfeng.spring.beans.definitions.BeanDefinition;
import org.lyfeng.spring.beans.definitions.BeanDefinitionRegistry;
import org.lyfeng.spring.exception.BeanDefinitionExcetion;
import org.lyfeng.spring.exception.BeansCreateException;
import org.lyfeng.spring.exception.BeansExceptions;
import org.lyfeng.spring.exception.NoSuchBeanDefinitionException;
import org.lyfeng.spring.utils.ClassType;
import org.lyfeng.spring.utils.ClassUtils;

/**
 * @author leiyufeng
 * 2013-4-22 下午3:15:53
 */
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory,BeanDefinitionRegistry{
	
	/**beanDefinitionsMap's lock**/
	private Lock beanDefinitionMapLock=new ReentrantLock(); 
	private final Map<String,BeanDefinition> beanDefinitionsMap=new ConcurrentHashMap<String,BeanDefinition>();
	@Override
	public Object getBean(String name) throws BeansExceptions {
		Object obj=null;
		//从代理结构中查找，如果未找到
		//则从单例bean结构中查找
		if(null==(obj=getProxyObject(name)))
		{
			obj=singletonObjectsMap.get(name);
		}
		if(null==obj)
		{
			throw new NoSuchBeanDefinitionException(String.format("bean [%s]不存在", name));
		}
		return obj;
	}

	@Override
	public <T> T getBean(Class<T> requiredType) throws BeansExceptions {
		return null;
	}

	@Override
	public boolean containsBean(String name) {
		return super.containsSingleton(name);
	}

	@Override
	public void registerBeanDefinition(String beanName,
			BeanDefinition beanDefinition) throws BeanDefinitionExcetion {
		beanDefinitionMapLock.lock();
		try{
			beanDefinitionsMap.put(beanName, beanDefinition);
		}finally{
			beanDefinitionMapLock.unlock();
		}
	}

	@Override
	public void removeBeanDefinition(String beanName)
			throws BeanDefinitionExcetion {
		beanDefinitionMapLock.lock();
		try{
			beanDefinitionsMap.remove(beanName);
		}finally{
			beanDefinitionMapLock.unlock();
		}
	}

	@Override
	public BeanDefinition getBeanDefinition(String beanName)
			throws BeanDefinitionExcetion {
		return beanDefinitionsMap.get(beanName);
	}

	@Override
	public boolean containsBeanDefinition(String beanName) {
		return beanDefinitionsMap.containsKey(beanName);
	}
	/**
	 * 执行初始化操作
	 */
	@Override
	public boolean refresh() {
		//创建容器中所有的bean
		createBeans();
		//解决依赖
		createContext();
		//创建aspect
		createAspect();
		//resolve aspect
		resolveAspect();
		return true;
	}
	@SuppressWarnings("rawtypes")
	protected void createBeans()
	{
		Iterator it=beanDefinitionsMap.entrySet().iterator();
		//创建component bean
		while(it.hasNext())
		{
			Map.Entry entry=(Map.Entry)it.next();
			@SuppressWarnings("unused")
			String key=(String)entry.getKey();
			BeanDefinition value=(BeanDefinition)entry.getValue();
			createBean(value);
		}
	}
	@SuppressWarnings("rawtypes")
	protected void createAspect()
	{
		Iterator it=super.aspectDefinitionsMap.entrySet().iterator();
		while(it.hasNext())
		{
			Map.Entry entry=(Map.Entry)it.next();
			@SuppressWarnings("unused")
			String key=(String)entry.getKey();
			BeanDefinition value=(BeanDefinition)entry.getValue();
			createBean(value);
		}
	}
	/**
	 * 执行注入操作
	 * @param target 需要注入的对象
	 * @param injectedBean 被注入的对象
	 * @param field target中对应的字段
	 * @throws BeansExceptions
	 */
	abstract public void autowireBean(Object target,Object injectedBean,String field) throws BeansExceptions;
	/**
	 * 创建ioc容器，解决依赖关系
	 */
	protected void createContext()
	{
		for(String registerBean:registeredSingletons)
		{
			Object targetObj=singletonObjectsMap.get(registerBean);
			Set<String> deptBeans=dependentBeanMap.get(registerBean);
			//执行注入操作
			if(null==deptBeans)
				continue;
			//解决依赖关系
			for(String injectedBean:deptBeans)
			{
				Object deptObj=null;
				if(null==(deptObj=getProxyObject(injectedBean)))
				{
					deptObj=singletonObjectsMap.get(injectedBean);
				}
				if(null==deptObj)
				{
					throw new NoSuchBeanDefinitionException(String.format("bean [%s]不存在", injectedBean));
				}
				autowireBean(targetObj, deptObj, injectedBean);
			}
		}
	}
	@Override
	public <T> T createBean(BeanDefinition beanDefinition) throws BeansExceptions {
		try {
			Class<T> beanClass=beanDefinition.getResolvedClass();
			T object=beanClass.newInstance();
			String beanName=beanDefinition.getBeanName();
			
			ClassType classType=ClassUtils.getClassType(beanClass);
			switch (classType) {
			case Aspect:
				super.addAspectBean(beanName, object);
				break;
			case Component:
				super.addSingleton(beanName, object);
				break;
			default:
				break;
			}
			return object;
		} catch (InstantiationException | IllegalAccessException e) {
			// TODO Auto-generated catch block
			throw new BeansCreateException(e.getMessage(),e);
		}
	}
	
}
